/**
 * @Copyright ®2015 Sinosoft Co. Ltd. All rights reserved.<br/>
 * 项目名称 : 电子商务云服务平台
 * 创建日期 : 2016年6月28日
 * 修改历史 : 
 *     1. [2016年6月30日]修改文件 by chihouliang
 * 添加Javadoc注释，更新代码规范，静态工具类增加private构造函数。<br/>
 * 校验代码合并，并删除字符串的非空校验（使用StringUtil）
 */
package com.gavinwind.inspay.common.util;

import org.apache.commons.validator.GenericValidator;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 属性校验工具类，例如校验邮箱格式，手机号等。如果需要校验字符串是否为空，使用StringUtil工具类
 * @date 2010-11-25
 * @since JDK 1.5
 * @author dingkui
 * @version 1.0
 * 
 */
public class ValidateUtil extends GenericValidator {
    
    private ValidateUtil() {}

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 2350196588312183462L;

    /**
     * 判断字符串非空 字符串为null或""的时候返回false，否则为true，字符串校验使用StringUtil判断，此方法可能将被删除
     * 
     * @param cValue
     *            待校验字符串
     * @return 空时返回true
     */
    @Deprecated
    public static boolean isNotNullOrEmpty(String cValue) {
        return !GenericValidator.isBlankOrNull(cValue);
    }

    /**
     * 判断字符串是否合法的邮件地址 合法，则返回true
     * 
     * @param cEmail
     *            邮件地址
     * @return 合法邮件地址时返回true
     */
    public static boolean isEmail(String cEmail) {
        return GenericValidator.isEmail(cEmail);
    }

    /**
     * 验证邮编是否有效 有效返回true
     * 
     * @param cZip
     *            邮编
     * @return 邮编格式正确返回true
     */
    public static boolean isZipValid(String cZip) {
        boolean tRetval = false;
        if (null != cZip) {
            String tZipCodePattern = "\\d{5}(-\\d{4})?";
            String tZipCodePattern1 = "\\d{6}";
            tRetval = cZip.matches(tZipCodePattern) || cZip.matches(tZipCodePattern1);
        }
        return tRetval;
    }

    //    /** 
    //     * 判断是否为正确的邮件格式 
    //     * @param str 需要验证的字符串
    //     * @return 邮件格式时返回true 
    //     */  
    //    public static boolean isEmail(String str){  
    //        if(isEmpty(str))  
    //            return false;  
    //        return str.matches("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$");  
    //    }  

    /** 
     * 判断字符串是否为合法手机号 11位 13 14 15 18开头 
     * @param cStr 需要验证的字符串
     * @return <code>true</code>手机号正确
     */
    public static boolean isMobile(String cStr) {
        if (StringUtil.isBlank(cStr))
            return false;
        return cStr.matches("^(13|14|15|18)\\d{9}$");
    }

    /** 
     * 判断是否为数字 
     * @param cStr 需要验证的字符串
     * @return true 数字时
     */
    public static boolean isNumber(String cStr) {
        try {
            Integer.parseInt(cStr);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    /** 
     * 判断是否为浮点数或者整数 
     * @param cStr 需要验证的字符串
     * @return true 浮点数
     */
    public static boolean isNumeric(String cStr) {
        Pattern tPattern = Pattern.compile("^(-?\\d+)(\\.\\d+)?$");
        Matcher tIsNum = tPattern.matcher(cStr);
        if (!tIsNum.matches()) {
            return false;
        }
        return true;
    }

    /**
     * 固定值判断 value同standard一致，则返回ture，字符串判读处理放入StringUtil工具类中
     * 
     * @param cValue
     *            输入String
     * @param cStandard
     *            标准值
     * @return 两个值相同时返回true
     * @see StringUtil
     */
    @Deprecated
    public static boolean validatorEqualEVoiceValue(String cValue, String cStandard) {
        if (null == cValue && null == cStandard) {
            return true;
        } else if (null == cValue || null == cStandard) {
            return false;
        } else {
            return cValue.equals(cStandard);
        }
    }

    /**
     * 验证字符串长度 value的长度为len，返回true
     * 
     * @param cValue
     *            字符串
     * @param cLen
     *            指定长度
     * @return 字符串长度与传入len相同返回true
     */
    @Deprecated
    public static boolean validatorLength(String cValue, int cLen) {
        return cValue.length() == cLen;
    }

    /**
     * 验证字符串是否由字母和数字组成 全由字母和数字，则返回true
     * 
     * @param cStr
     *            验证字符串
     * @return 字符串全部由字母+数字组成，返回true
     */
    public static boolean validatorStringIsNumOrLetter(String cStr) {
        int j = 0;
        for (int i = 0; i < cStr.length(); i++) {
            if ((cStr.charAt(i) >= '0' && cStr.charAt(i) <= '9') || (cStr.charAt(i) >= 'a' && cStr.charAt(i) <= 'z')
                    || (cStr.charAt(i) >= 'A' && cStr.charAt(i) <= 'Z')) {
                j = j + 1;
            }
        }
        // 格式正确
        if (j == cStr.length()) {
            return true;
        }
        // 格式不对
        else {
            return false;
        }
    }

    /**
     * 验证证件号、证件类型、性别和生日是否正确 验证正确，返回true
     * 
     * @param cIdno
     *            证件号码
     * @param cIdtype
     *            证件类型
     * @param cSex
     *            性别
     * @param cBirthday
     *            生日
     * @return 校验字符串通过时返回true
     */
    public static boolean checkIdCardWithSexAndBirthday(String cIdno, String cIdtype, String cSex, String cBirthday) {
        // throws Exception

        // 如果证件类型为身份证
        if (cIdtype != null && cIdtype.trim().equals("0")) {
            String tTmpbirthday = "";
            String tSex = "";
            // 截取身份证中的性别码和生日码
            if (cIdno.trim().length() == 18) {
                tTmpbirthday = cIdno.substring(6, 14);
                tSex = cIdno.substring(16, 17);
            } else if (cIdno.trim().length() == 15) {
                tTmpbirthday = cIdno.substring(6, 12);
                tTmpbirthday = "19" + tTmpbirthday;
                tSex = cIdno.substring(14, 15);
            } else {
                return false;
            }
            if (cBirthday == null || cBirthday.equals("")) {
                return false;
            }
            if (cBirthday.compareTo(cBirthday) != 0) {
                return false;
            }
            if (tSex.equals("0") || tSex.equals("2") || tSex.equals("4") || tSex.equals("6") || tSex.equals("8")) {
                if (cSex == null || cSex.trim().equals("0")) {
                    return false;
                }
            } else {
                if (cSex == null || cSex.trim().equals("1")) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 验证身份证长度 长度为15或18位，则返回true
     * 
     * @param cIdno
     *            身份证号码
     * @return 省份证号为15或18位返回true
     */
    public static boolean checkIdCardLength(String cIdno) {
        if (cIdno.trim().length() == 18) {
            return true;
        } else if (cIdno.trim().length() == 15) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 验证身份证与性别组合是否正确 正确，则返回true
     * 
     * @param cIdno
     *            身份证号
     * @param cSex
     *            性别，只能是0,1
     * @return 验证身份证与性别组合是否正确 正确，则返回true
     */
    public static boolean checkIdCardWithcSex(String cIdno, String cSex) {
        String tSex = "";
        if (cIdno.trim().length() == 18) {
            tSex = cIdno.substring(16, 17);
        } else if (cIdno.trim().length() == 15) {
            tSex = cIdno.substring(14, 15);
        } else {
            return false;
        }
        if (tSex.equals("0") || tSex.equals("2") || tSex.equals("4") || tSex.equals("6") || tSex.equals("8")) {
            if (cSex == null || cSex.trim().equals("0")) {
                return false;
            }
        } else {
            if (cSex == null || cSex.trim().equals("1")) {
                return false;
            }
        }
        return true;
    }

    /**
     * 验证身份证与出生日期组合正确 正确，则返回true
     * 
     * @param cIdno
     *            身份证号
     * @param cBirthday
     *            生日
     * @return 生日正确时返回true
     */
    public static boolean checkIdCardWithBirthday(String cIdno, String cBirthday) {
        String tBirthday = "";
        if (cIdno.trim().length() == 18) {
            tBirthday = cIdno.substring(6, 14);
        } else if (cIdno.trim().length() == 15) {
            tBirthday = cIdno.substring(6, 12);
            tBirthday = "19" + tBirthday;
        } else {
            return false;
        }
        if (cBirthday.compareTo(tBirthday) != 0) {
            return false;
        }
        return true;
    }

    /**
     * 严格校验身份证号码 身份证号码正确，返回true
     * 
     * @param cIdCard
     *            身份证号码
     * @return 身份证号码正确时返回true
     */
    public static boolean checkIdCard(String cIdCard) {
        String tSystemDate = DateUtil.getCurrentDate("yyyyMMdd");
        int tYear = Integer.parseInt(tSystemDate.substring(0, 4));
        int tMonth = Integer.parseInt(tSystemDate.substring(4, 6)) + 1;
        final int tDay = Integer.parseInt(tSystemDate.substring(6));
        int tYyyy; // 年
        int tMm; // 月
        int tDd; // 日
        int tIdLength = cIdCard.length();
        if (tIdLength == 0) {
            return false;
        }
        if (tIdLength != 15 && tIdLength != 18) {
            return false;
        }
        if (tIdLength == 15) {
            char[] tCode = cIdCard.toUpperCase().toCharArray();
            int tASC;
            for (int i = 0; i < tIdLength; i++) {
                // 通过ASC码表进行识别
                tASC = (int) tCode[i];
                // 不属于数字的都是非法的 数字0-9的ASC码表位于48-57之间
                if (tASC < 48 || tASC > 57) {
                    return false;
                }
            }
            tYyyy = Integer.parseInt("19" + cIdCard.substring(6, 8));
            tMm = Integer.parseInt(cIdCard.substring(8, 10));
            tDd = Integer.parseInt(cIdCard.substring(10, 12));
            if (tMm > 12 || tMm <= 0) {
                return false;
            }
            if (tDd > 31 || tDd <= 0) {
                return false;
            }
            // 4,6,9,11月份日期不能超过30
            if ((tMm == 4 || tMm == 6 || tMm == 9 || tMm == 11) && (tDd > 30)) {
                return false;
            }
            // 判断2月份
            if (tMm == 2) {
                if (DateUtil.isLeapYear(tYyyy)) {
                    if (tDd > 29) {
                        return false;
                    }
                } else {
                    if (tDd > 28) {
                        return false;
                    }
                }
            }
        } else {
            char[] tCode = cIdCard.toUpperCase().toCharArray();
            int tASC;
            for (int i = 0; i < tIdLength - 1; i++) {
                // 通过ASC码表进行识别
                tASC = (int) tCode[i];
                // 不属于数字的都是非法的 数字0-9的ASC码表位于48-57之间
                if (tASC < 48 || tASC > 57) {
                    return false;
                }
            }
            tASC = (int) tCode[17];
            if (tASC < 48 || tASC > 57) {
                if (!cIdCard.substring(17).equals("X") && !cIdCard.substring(17).equals("x")) {
                    return false;
                }
            }
            if (cIdCard.indexOf("X") > 0 && cIdCard.indexOf("X") != 17 || cIdCard.indexOf("x") > 0 && cIdCard.indexOf("x") != 17) {
                return false;
            }
            tYyyy = Integer.parseInt(cIdCard.substring(6, 10));
            if (tYyyy > tYear || tYyyy < 1900) {
                return false;
            }
            tMm = Integer.parseInt(cIdCard.substring(10, 12));
            if (tMm > 12 || tMm <= 0) {
                return false;
            }
            if (tYyyy == tYear && tMm > tMonth) {
                return false;
            }
            tDd = Integer.parseInt(cIdCard.substring(12, 14));
            return false;
        }
        // 4,6,9,11月份日期不能超过30
        if ((tMm == 4 || tMm == 6 || tMm == 9 || tMm == 11) && (tDd > 30)) {
            return false;
        }
        // 判断2月份
        if (tMm == 2) {
            if (DateUtil.isLeapYear(tYyyy)) {
                if (tDd > 29) {
                    return false;

                }
            } else {
                if (tDd > 28) {
                    return false;
                }
            }
        }
        if (tYyyy == tYear && tMm == tMonth && tDd > tDay) {
            return false;
        }
        if (cIdCard.substring(17).equals("x") || cIdCard.substring(17).equals("X")) {
            if (!getVerifyBit(cIdCard).equals("x") && !getVerifyBit(cIdCard).equals("X")) {
                return false;
            }
        } else {
            if (!cIdCard.substring(17).equals(getVerifyBit(cIdCard))) {
                return false;

            }
        }
        return true;
    }

    /**
     * 计算身份证校验码 原理: ∑(a[i]*W[i]) mod 11 ( i = 2, 3, ..., 18) (1) "*" 表示乘号 i--------表示身份证号码每一位的序号，从右至左，最左侧为18，最右侧为1。
     * a[i]-----表示身份证号码第 i 位上的号码 W[i]-----表示第 i 位上的权值 W[i] = 2^(i-1) mod 11 计算公式 (1) 令结果为 R 根据下表找出 R
     * 对应的校验码即为要求身份证号码的校验码C。 R 0 1 2 3 4 5 6 7 8 9 10 C 1 0 X 9 8 7 6 5 4 3 2 X 就是 10，罗马数字中的 10 就是 X 15位转18位中,计算校验位即最后一位
     * 
     * @param cCard
     *            身份证号码
     * @return 校验码
     */
    public static String getVerifyBit(String cCard) {
        String tResult = null;

        int tNum = Integer.parseInt(cCard.substring(0, 1)) * 7 + Integer.parseInt(cCard.substring(1, 2)) * 9 + Integer.parseInt(cCard.substring(2, 3)) * 10
                + Integer.parseInt(cCard.substring(3, 4)) * 5 + Integer.parseInt(cCard.substring(4, 5)) * 8 + Integer.parseInt(cCard.substring(5, 6)) * 4
                + Integer.parseInt(cCard.substring(6, 7)) * 2 + Integer.parseInt(cCard.substring(7, 8)) * 1 + Integer.parseInt(cCard.substring(8, 9)) * 6
                + Integer.parseInt(cCard.substring(9, 10)) * 3 + Integer.parseInt(cCard.substring(10, 11)) * 7 + Integer.parseInt(cCard.substring(11, 12)) * 9
                + Integer.parseInt(cCard.substring(12, 13)) * 10 + Integer.parseInt(cCard.substring(13, 14)) * 5
                + Integer.parseInt(cCard.substring(14, 15)) * 8 + Integer.parseInt(cCard.substring(15, 16)) * 4
                + Integer.parseInt(cCard.substring(16, 17)) * 2;
        tNum = tNum % 11;
        switch (tNum) {
        case 0:
            tResult = "1";
        break;
        case 1:
            tResult = "0";
        break;
        case 2:
            tResult = "X";
        break;
        case 3:
            tResult = "9";
        break;
        case 4:
            tResult = "8";
        break;
        case 5:
            tResult = "7";
        break;
        case 6:
            tResult = "6";
        break;
        case 7:
            tResult = "5";
        break;
        case 8:
            tResult = "4";
        break;
        case 9:
            tResult = "3";
        break;
        case 10:
            tResult = "2";
        break;
        }
        return tResult;
    }

    /**
     * 判断10位字符串是否是日期 例如：1983-16-35就不是日期
     * 
     * @param cStrNum
     *            待验证的字符串
     * @return 判断10位字符串为正确日期返回true
     */
    public static boolean checkNum(String cStrNum) {
        if (cStrNum == null || cStrNum.equals("")) {
            return false;
        }
        int tYear = Integer.parseInt(cStrNum.substring(0, 4));
        int tMon = Integer.parseInt(cStrNum.substring(5, 7));
        int tDay = Integer.parseInt(cStrNum.substring(8, 10));

        if (tMon > 12 || tMon < 1 || tYear < 1) {
            return false;
        } else {
            if (tMon == 1 || tMon == 3 || tMon == 5 || tMon == 7 || tMon == 8 || tMon == 10 || tMon == 12) {
                if (tDay < 1 || tDay > 31) {
                    return false;
                }

            }
            if (tMon == 4 || tMon == 6 || tMon == 9 || tMon == 11) {
                if (tDay < 1 || tDay > 30) {
                    return false;
                }
            }
            if (tMon == 2) {
                if (tYear % 400 == 0 | tYear % 100 != 0 & tYear % 4 == 0) {
                    if (tDay < 1 || tDay > 29) {
                        return false;
                    }
                } else {
                    if (tDay < 1 || tDay > 28) {
                        return false;
                    }
                }
            }
            return true;
        }
    }

    /**
     * 判断8位数是否是日期 例如：19831635就不是日期
     * 
     * @param cStrNum
     *            待验证的字符串
     * @return 8位日期如果正确返回true
     */
    public static boolean checkNumStr(String cStrNum) {
        if (cStrNum == null || cStrNum.equals("") || cStrNum.length() != 8 || !GenericValidator.isInt(cStrNum)) {
            return false;
        }
        int tYear = Integer.parseInt(cStrNum.substring(0, 4));
        int tMon = Integer.parseInt(cStrNum.substring(4, 6));
        int tDay = Integer.parseInt(cStrNum.substring(6, 8));

        if (tMon > 12 || tMon < 1 || tYear < 1) {
            return false;
        } else {
            if (tMon == 1 || tMon == 3 || tMon == 5 || tMon == 7 || tMon == 8 || tMon == 10 || tMon == 12) {
                if (tDay < 1 || tDay > 31) {
                    return false;
                }

            }
            if (tMon == 4 || tMon == 6 || tMon == 9 || tMon == 11) {
                if (tDay < 1 || tDay > 30) {
                    return false;
                }
            }
            if (tMon == 2) {
                if (tYear % 400 == 0 | tYear % 100 != 0 & tYear % 4 == 0) {
                    if (tDay < 1 || tDay > 29) {
                        return false;
                    }
                } else {
                    if (tDay < 1 || tDay > 28) {
                        return false;
                    }
                }
            }
            return true;
        }
    }

}
